home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / dbdoc.zip / MEMDOC.C < prev    next >
C/C++ Source or Header  |  1991-12-08  |  14KB  |  545 lines

  1. /**************************************/
  2. /*       memdoc.c                     */
  3. /*   dBASE memo file reader           */
  4. /*   Programmer:  Jay Parsons         */
  5. /*   Version 1.1   12/08/91              */
  6. /*                                                  */
  7. /*      Changes in 1.1:                          */
  8. /*           removed incorrect rounding   */
  9. /*   procedure in do_float_var        */
  10. /*   and replaced it with change      */
  11. /*   to the print formatting string   */
  12. /**************************************/
  13.  
  14. #include "ctype.h"
  15. #include "math.h"
  16. #include "stdio.h"
  17. #include "string.h"
  18.  
  19. /**************************************/
  20. /*       define statememts            */
  21. /**************************************/
  22.  
  23. #define JULBASE         1721060         /* dBASE Julian for 01/01/0000      */
  24. #define FOURCENTS        146097         /* days in 400 years                */
  25. #define SHORTCENT         36524         /* days in 100 years if not /400    */
  26. #define FOURYEARS          1461         /* days in 4 years with a leap year */
  27. #define SHORTYEAR           365         /* days in a year not a leap year   */
  28.  
  29. #define ENDFILE           0x1A
  30. #define MAXNAME             11          /* max size of variable name + 1 */
  31. #define HEADERLEN           32          /* sizeof( struct memheader )    */
  32. #define PUBLIC               0
  33.  
  34. #define FALSE                0
  35. #define TRUE                 1
  36.  
  37. /**************************************/
  38. /*       global declarations          */
  39. /**************************************/
  40.  
  41. struct memheader
  42. {
  43.     char name[MAXNAME];             /* variable name */
  44.     char type;                      /* array, char, date, float, num or logic */
  45.     unsigned long dataptr;          /* useless except 1=bcd, 2=int for dB IV */
  46.     char size;
  47.     char decimals;
  48.     char scope;                     /* public or private */
  49.     char wasted1[13];
  50. } var;
  51.  
  52. int arr1_subscr, arr2_subscr, dim_1, dim_2, inarray;
  53. extern char file_name[], message[], tempbuff[];
  54.  
  55. /**************************************/
  56. /*       function declarations        */
  57. /**************************************/
  58.  
  59. int memdoc( char *file_name );
  60. int nextvar( FILE *ifile, int inarray );
  61.  
  62. int do_array( FILE *ifile );
  63. int do_bcd_var( FILE *ifile );
  64. int do_char_var( FILE *ifile );
  65. int do_date_var( FILE *ifile );
  66. int do_float_var( FILE *ifile );
  67. int do_logic_var( FILE *ifile );
  68. int do_num_var( FILE *ifile );
  69.  
  70. char *dtoc( double jul );
  71. char *dow( double jul );
  72.  
  73. /******************************************/
  74. /*     int memdoc (char *file_name)       */
  75. /*  Principal routine of this module.     */
  76. /* Attempts to open mem file "file_name." */
  77. /* If successful, prints it until reaching*/
  78. /* any error or variable of unknown type. */
  79. /* Closes file and returns 0 or error.    */
  80. /******************************************/
  81.  
  82. int memdoc( char *file_name )
  83. {
  84.     int i;
  85.     FILE *ifile;
  86.  
  87.     if ( ( ifile = fopen( file_name, "rb" ) ) == NULL )
  88.     {  sprintf( message, "Unable to open file %s for reading", file_name );
  89.         return( 1 );
  90.     }
  91.  
  92.     inarray = FALSE;
  93.     while ( ! ( i = nextvar( ifile, inarray ) ) )
  94.         printit( i );
  95.     fclose( ifile );
  96.     return ( i == 2 ? 0 : i );
  97. }
  98.  
  99. /******************************************/
  100. /*  int nextvar( ifile, inarray )         */
  101. /* Reads 32 characters of "ifile" as the  */
  102. /* the header of a memvar.  Returns 1 if  */
  103. /* not a .mem file or error, 2 at eof()   */
  104. /* else 0.                                */
  105. /* Analyzes header, prints name and type, */
  106. /* and calls appropriate routine to read  */
  107. /* and display data for the type.  The    */
  108. /* called routine moves the ifile pointer */
  109. /* to end of data, which should be start  */
  110. /* of next header or ENDFILE.             */
  111. /* Omits name of variable and substitutes */
  112. /* array address for array elements, due  */
  113. /* to parameter "inarray".                */
  114. /******************************************/
  115.  
  116. int nextvar( FILE *ifile, int inarray )
  117. {
  118.     /* "F" and "N" routines reversed for dBASE quirk */
  119.     char z = ' ', *ptr, vartypes[] = "ACDNLF";
  120.     int (*do_ptr[]) () = { do_array, do_char_var,
  121.                                     do_date_var, do_float_var,
  122.                                     do_logic_var, do_num_var };
  123.  
  124.     /* read the next header; return 2 for EOF, 1 for other error */
  125.     switch ( fread( &var, 1, HEADERLEN, ifile ) )
  126.     {
  127.         case HEADERLEN :
  128.             break;
  129.         case 0         :
  130.             if ( getch( ifile ) == EOF )
  131.                 return 2;
  132.             else
  133.             {
  134.                 sprintf( message, "Error reading .mem file %s", file_name );
  135.                 return 1;
  136.             }
  137.         case 1         :
  138.             /* if only char not ENDFILE, fall thru to default */
  139.             if ( var.name[0] == ENDFILE )
  140.                 return 2;
  141.         default        :
  142.         {
  143.             sprintf( message, "Error reading .mem file %s", file_name );
  144.             return 1;
  145.         }
  146.     }
  147.  
  148.     /* get the type bit and pointer to it in vartypes string */
  149.     z = var.type & 127;         /* strip high bit */
  150.     ptr = strchr( vartypes, (int) z );
  151.  
  152.     /* if variable is no known dBase var type */
  153.     if ( ptr == NULL )
  154.     {
  155.         sprintf( message, "Not a .mem file" );
  156.         return 1;
  157.     }
  158.  
  159.     /* add variable name, or if an array element, its address  */
  160.     if ( !inarray )
  161.         /* sprintf() spec %-12s takes care of padding */
  162.         sprintf( message, "%-12s ", var.name );
  163.     else
  164.     {
  165.         if ( var.name[0] != '[' )
  166.         {
  167.             sprintf( message, "Too few elements for declared array!" );
  168.             return 1;
  169.         }
  170.         if ( !arr2_subscr )              /* one-dimensional array */
  171.             sprintf( tempbuff, "        [%d]   ", arr1_subscr) ;
  172.         else                             /* two-dimensional array */
  173.             sprintf( tempbuff, "     [%d,%d]   ", arr1_subscr, arr2_subscr );
  174.         strcpy( message, tempbuff );
  175.     }
  176.  
  177.     /* add scope and type - all non-public levels are "private" */
  178.  
  179.     if ( inarray )
  180.         strcat( message, "  elem  " );
  181.     else
  182.     {
  183.         sprintf( tempbuff, "  %s   ",var.scope == PUBLIC ? "pub" : "prv" );
  184.         strcat( message, tempbuff );
  185.     }
  186.  
  187.     sprintf( tempbuff, "%c   ", ( z == 'N' ? 'F' : z == 'F' ? 'N' : z ) );
  188.     strcat( message, tempbuff );
  189.  
  190.     /* now, finally, deal with each type of data as required */
  191.     return ( ( *do_ptr[ptr - vartypes] ) ( ifile ) );
  192. }
  193.  
  194. /***************************************/
  195. /*    do_array()                       */
  196. /***************************************/
  197. int do_array( FILE *ifile )
  198. {
  199.     int err;
  200.  
  201.     /* read dimensions (backwards due to C evaluation order) */
  202.     if ( fread( &dim_2, 2, 1, ifile ) + fread( &dim_1, 2, 1, ifile ) != 2 )
  203.     {
  204.         sprintf( message, "Unable to read array dimensions" );
  205.         return 1;
  206.     }
  207.     /* add dimensions as data for A type */
  208.     if ( dim_2 )
  209.     {
  210.         sprintf( tempbuff, "[%d,%d]", dim_1, dim_2 );
  211.         strcat( message, tempbuff );
  212.     }
  213.     else
  214.     {
  215.         arr2_subscr = 0;
  216.         sprintf( tempbuff, "[%d]", dim_1 );
  217.         strcat( message, tempbuff );
  218.     }
  219.  
  220.     inarray = TRUE;
  221.     printit( 0 );
  222.  
  223.     /* get elements, almost but not exactly like other data */
  224.     for ( arr1_subscr = 1; arr1_subscr <= dim_1; arr1_subscr++ )
  225.         if ( !dim_2 )
  226.         {
  227.             err = nextvar( ifile, inarray );
  228.             printit( err );
  229.             if ( err )
  230.                 return err;
  231.         }
  232.         else
  233.             for (arr2_subscr = 1; arr2_subscr <= dim_2; arr2_subscr++ )
  234.             {
  235.                 err = nextvar( ifile, inarray );
  236.                 printit( err );
  237.                 if ( err )
  238.                     return err;
  239.             }
  240.     inarray = FALSE;
  241.     *message = '\0';        /*  suppress extra line feed on return */
  242.     return 0;
  243. }
  244.  
  245. /***************************************/
  246. /*    do_char_var()                    */
  247. /***************************************/
  248.  
  249. int do_char_var( FILE *ifile )
  250. {
  251.     int spaces;
  252.     char *c;
  253.  
  254.     if ( fread( tempbuff, var.size, 1, ifile ) != 1 )
  255.     {
  256.         strcpy( message, "Unable to read character variable" );
  257.         return 1;
  258.     }
  259.     strcat( message, "\"" );
  260.     strcat( message, tempbuff );
  261.     strcat( message, "\"" );
  262.     return 0;
  263. }
  264.                                           
  265. /***************************************/
  266. /*    do_date_var()                    */
  267. /*                                     */
  268. /* The value of a null date is 10^100  */
  269. /***************************************/
  270.  
  271. int do_date_var( FILE *ifile )
  272.  
  273. {
  274.     double julian;
  275.     char *days[] =      { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" } ;
  276.  
  277.     if ( fread( &julian, 8, 1, ifile ) !=1 )
  278.     {
  279.         strcpy( message, "Can't read a date" );
  280.         return 1;
  281.     }
  282.  
  283.     if ( julian <= JULBASE + SHORTCENT )     /* January 1, 100 */
  284.     {
  285.         strcpy( message, "Not a valid dBASE date" );
  286.         return 1;
  287.     }
  288.  
  289.     if ( julian == 1.e100 )
  290.         strcat( message, "{  /  /  }" );
  291.     else
  292.     {
  293.         strcat( message, days[ ( ( unsigned long ) julian + 1 ) % 7 ] );
  294.         strcat( message, ", " );
  295.         strcat( message, dtoc( julian ) );
  296.     }
  297.     return 0;
  298. }
  299.  
  300. /***************************************/
  301. /*    dtoc( julian )                   */
  302. /*                                     */
  303. /*  Convert a date given as a dBASE    */
  304. /*  Julian double into "1 Oct 1990"    */
  305. /*                                     */
  306. /*  There are shorter algorithms, but  */
  307. /*  they are much less intuitive.      */
  308. /***************************************/
  309.  
  310. char *dtoc( double julian )
  311. {
  312.  
  313.     int daysin[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  314.     char *month[]  = { "Jan","Feb","Mar","Apr",
  315.                              "May","Jun","Jul","Aug",
  316.                              "Sep","Oct","Nov","Dec" };
  317.     char *ptr, strdate[12];
  318.     unsigned int era, cent, quad, leap, yr, year, mo = 0;
  319.     unsigned long tempdate;
  320.  
  321.     /* adjust number in tempdate to days since end of 1 BC  */
  322.     tempdate = ( unsigned long ) julian - JULBASE;
  323.  
  324.     /* find number of four-century eras A.D. and adjust     */
  325.     era = tempdate / FOURCENTS;
  326.     year = 400 * era;
  327.     tempdate %= FOURCENTS;
  328.  
  329.     /* first year of each 400 is a leap year                */
  330.     if ( tempdate < 366 )
  331.         leap = 1;
  332.     else
  333.     /* adjust to pretend all centuries are short ones       */
  334.     {
  335.         tempdate -= 1;
  336.         cent = tempdate / SHORTCENT;
  337.         year += cent * 100;
  338.         tempdate %= SHORTCENT;
  339.  
  340.         /* first year of century is nonleap, else adjust back   */
  341.         if ( tempdate < 365 )
  342.             leap = 0;
  343.         else
  344.         {
  345.             tempdate += 1;
  346.             quad = tempdate / FOURYEARS;
  347.             year += quad * 4;
  348.             tempdate %= FOURYEARS;
  349.             /* first year of each four is a leap year, so adjust    */
  350.             if ( tempdate > 365 )
  351.             {
  352.                 tempdate -= 1;
  353.                 yr = tempdate / SHORTYEAR;
  354.                 year += yr;
  355.                 tempdate %= SHORTYEAR;
  356.             }
  357.             leap = !( year % 4 );
  358.         }
  359.     }
  360.  
  361.     /* convert from offset 0 into year to day 1, etc.       */
  362.     tempdate += 1;
  363.  
  364.     /* mo[1] is the second month in C, Feb. 29 is day 60    */
  365.     if ( leap && ( tempdate == 60 ) )
  366.     {
  367.         mo = 1;
  368.         tempdate =  29;
  369.     }
  370.     else
  371.     {
  372.         /*  subtract Feb. 29 if our date is later               */
  373.         if ( leap && ( tempdate > 60 ) )
  374.             tempdate--;
  375.  
  376.         for ( ; tempdate > daysin[mo]; tempdate -= daysin[mo], mo++ )
  377.             ;
  378.     }
  379.  
  380.     ltoa( tempdate, tempbuff, 10 );
  381.     strcpy( strdate, tempbuff );
  382.     strcat( strdate, " " );
  383.     strcat( strdate, month[mo] );
  384.     strcat( strdate, ", " );
  385.     itoa( year, tempbuff, 10 );
  386.     strcat( strdate, tempbuff );
  387.     return strdate;
  388. }
  389.  
  390. /***************************************/
  391. /*    do_float_var()                   */
  392. /***************************************/
  393.  
  394. int do_float_var( FILE *ifile )
  395. {
  396.     double fvar;
  397.     char prefix[] = "% G.";
  398.     char format[8];
  399.  
  400.     if ( fread( &fvar, 8, 1, ifile ) != 1 )
  401.     {
  402.         strcpy( message, "Can't read a float value" );
  403.         return 1;
  404.     }
  405.  
  406.     strcpy( format, prefix );
  407.  
  408.     /* round off decimals beyond those specified    */
  409.     sprintf( tempbuff, "%d", var.decimals );
  410.     strcat( format, tempbuff );
  411.  
  412.     sprintf( tempbuff, format, fvar );
  413.     strcat( message, tempbuff );
  414.     return 0;
  415. }
  416.                                           
  417. /***************************************/
  418. /*    do_logic_var()                   */
  419. /***************************************/
  420.  
  421. int do_logic_var( FILE *ifile )
  422.  
  423. {
  424.     unsigned char s;
  425.  
  426.     if ( fread( &s, 1, 1, ifile ) != 1 )
  427.     {
  428.         strcpy( message, "Can't read a logical value" );
  429.         return 1;
  430.     }
  431.     if ( s > 1 )
  432.     {
  433.         strcpy( message, "Not a valid logical value" );
  434.         return 1;
  435.     }
  436.     sprintf( tempbuff, "%s", s == FALSE ? ".F." : ".T." );
  437.     strcat( message, tempbuff );
  438.     return 0;
  439. }
  440.  
  441. /***************************************/
  442. /*    do_num_var()                     */
  443. /***************************************/
  444. int do_num_var( FILE * ifile )
  445. {
  446.     int numvar;
  447.  
  448.     if ( var.dataptr == 1 )
  449.         return do_bcd_var( ifile );
  450.  
  451.     if ( fread( &numvar, 2, 1, ifile ) !=1 )
  452.     {
  453.         strcpy( message, "Can't read integer" );
  454.         return 1;
  455.     }
  456.     sprintf( tempbuff, "%d", numvar );
  457.     strcat( message, tempbuff );
  458.     return 0;
  459. }
  460.  
  461. /***************************************/
  462. /*    do_bcd_var()                     */
  463. /***************************************/
  464.  
  465. int do_bcd_var( FILE *ifile )
  466.  
  467. {
  468.     int exponent, precision, place, signword;
  469.     register int i, j = 2;
  470.     char bcd[12], longnum[] = "                     ";
  471.  
  472.     if ( fread( bcd, 12, 1, ifile ) != 1 )
  473.     {
  474.         strcpy( message, "Can't read BCD number" );
  475.         return 1;
  476.     }
  477.     /* first bit is sign, then 5 precision and 10 exponent biased +308 */
  478.     signword = 256 * (int) bcd[1] + (int) bcd[0];
  479.     longnum[0] = ((signword & 0x8000) == 0) ? ' ' : '-';
  480.     precision = (signword >> 10) & 0x1F;
  481.     exponent = (signword & 0x3FF) - 308;
  482.  
  483.     /* we can ignore trailing zeroes within precision */
  484.     for ( i = (precision + 3)/2; i >= 2; precision-- )
  485.         if ( precision % 2 )
  486.             if ( (bcd[i] >> 4) )
  487.                 break;
  488.             else
  489.                 i--;
  490.         else
  491.             if ( (bcd[i] & 0x0F) )
  492.                 break;
  493.  
  494.     /* Place decimal point if necessary */
  495.     /* and add leading zeroes after decimal point */
  496.     if ( exponent > 20 || exponent < 1 )
  497.     {
  498.         longnum[1] = '.';
  499.         if ( exponent > 20 || precision - exponent > 19 )
  500.             place = 2;
  501.         else
  502.         {
  503.             place = 2 - exponent;
  504.             for ( i = 2; i < place; i++ )
  505.                 longnum[i] = '0';
  506.         }
  507.     }
  508.     else
  509.     {
  510.         place = 1;
  511.         if ( precision > exponent )
  512.             longnum[exponent+1] = '.';
  513.     }
  514.  
  515.     /* now add the digits, skipping over the decimal point */
  516.     for ( i = 1; i <= precision; i++ )
  517.     {
  518.         if ( longnum[place] == '.' )
  519.             place++;
  520.         if ( i % 2 )
  521.             longnum[place++] = 48 + ( bcd[j] >> 4 ) ;
  522.         else
  523.             longnum[place++] = 48 + ( bcd[j++] & 0x0F );
  524.     }
  525.  
  526.     /* add trailing zeroes if needed */
  527.     if ( exponent < 21 )
  528.     {
  529.         i = precision;
  530.         while ( exponent > i++ )
  531.             longnum[place++] = '0';
  532.     }
  533.     longnum[place] = '\0';
  534.     strcat( message, longnum );
  535.  
  536.     /* and exponent if any */
  537.     if ( exponent > 20 || precision - exponent > 18 )
  538.     {
  539.         sprintf( tempbuff, "E%+d", exponent );   /* show plus sign */
  540.         strcat( message, tempbuff );
  541.     }
  542.     return 0;
  543. }
  544. /*   EOF  */
  545.